package com.platform.lxh.netty;

import com.platform.lxh.netty.handler.ClientMessageHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * @create: 2021-03-10 20:13
 * @author: xiaoh.luo001@bkjk.com
 * @description:
 **/
public class Client {

    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    //用于关闭没有正常关闭的tcp连接，比如拔网线
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    //是否将小的数据包组装为更大的数据包然后进行发送，而不是输入一次发送一次
                    //虽然该nagle算法有效提高了网络的负载，但造成了延时，需要根据场景甄别是否配置
                    .option(ChannelOption.TCP_NODELAY, Boolean.TRUE)
                    //单次发送最大socket字节数(linux中默认最小值是2048)
                    .option(ChannelOption.SO_SNDBUF, 2048)
                    //单次接收最大socket字节数(linux中默认最小值是256)
                    //SO_SNDBUF和SO_RCVBUF都是读取的文件描述符，而linux中读取此值之后，还会*2 https://linux.die.net/man/7/socket
                    .option(ChannelOption.SO_RCVBUF, 2048)
                    .handler(new LoggingHandler(LogLevel.DEBUG))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 添加用于解决粘包和拆包问题的处理器
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
                            pipeline.addLast(new LengthFieldPrepender(4));
                            // 添加用于进行心跳检测的处理器
                            pipeline.addLast(new IdleStateHandler(1, 2, 0));
                            // 添加用于根据自定义协议将消息与字节流进行相互转换的处理器
                            pipeline.addLast(new StringDecoder());
                            pipeline.addLast(new StringEncoder());
                            // 添加客户端消息处理器
                            pipeline.addLast(new ClientMessageHandler());
                        }
                    });

            ChannelFuture future = bootstrap.connect("127.0.0.1", 8585).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}
